package manifests

import (
	blindagev1alpha1 "git.blindage.org/21h/redis-operator/pkg/apis/blindage/v1alpha1"

	v1 "k8s.io/api/apps/v1"
	corev1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

func GenerateDeployment(cr *blindagev1alpha1.Redis) v1.Deployment {

	// check affinity rules
	affinity := &corev1.Affinity{}
	if cr.Spec.SentinelAffinity != nil {
		affinity = cr.Spec.SentinelAffinity
	}

	resourcesLimits := corev1.ResourceList{}
	if cr.Spec.SentinelPodLimits != nil {
		resourcesLimits = *cr.Spec.SentinelPodLimits
	}

	resourcesRequests := corev1.ResourceList{}
	if cr.Spec.SentinelPodRequests != nil {
		resourcesRequests = *cr.Spec.SentinelPodRequests
	}

	ports := []corev1.ContainerPort{
		{
			Name:          "sentinel",
			ContainerPort: 26379,
			Protocol:      corev1.ProtocolTCP,
		},
	}

	image := "redis:latest"
	if cr.Spec.Image != "" {
		image = cr.Spec.Image
	}

	pullPolicy := corev1.PullIfNotPresent
	if cr.Spec.PullPolicy != nil {
		pullPolicy = *cr.Spec.PullPolicy
	}

	replicas := int32(1)
	if cr.Spec.RedisReplicas != nil {
		replicas = *cr.Spec.RedisReplicas
	}

	deployment := v1.Deployment{
		ObjectMeta: metav1.ObjectMeta{
			Name:      cr.Name + "-sentinel",
			Namespace: cr.ObjectMeta.Namespace,
			Labels:    BaseLabels(cr),
		},
		Spec: v1.DeploymentSpec{
			Selector: &metav1.LabelSelector{
				MatchLabels: BaseLabels(cr),
			},
			Replicas: &replicas,
			Strategy: v1.DeploymentStrategy{Type: v1.RollingUpdateDeploymentStrategyType, RollingUpdate: nil},
			Template: corev1.PodTemplateSpec{
				ObjectMeta: metav1.ObjectMeta{
					Labels: MergeLabels(BaseLabels(cr),
						map[string]string{"component": "sentinel"},
					),
				},

				Spec: corev1.PodSpec{
					Affinity: affinity,
					InitContainers: []corev1.Container{
						{
							Name:    "config",
							Image:   image,
							Command: []string{"/bin/cp", "/redis-ro/sentinel.conf", "/redis/sentinel.conf"},
							VolumeMounts: []corev1.VolumeMount{
								{
									Name:      "config-rw",
									MountPath: "/redis",
								},
								{
									Name:      "config-ro",
									MountPath: "/redis-ro",
								},
								{
									Name:      "data",
									MountPath: "/redis/data",
								},
							},
						},
					},
					Containers: []corev1.Container{
						{
							Name:            "sentinel",
							Image:           image,
							Command:         []string{"redis-server", "/redis/sentinel.conf", "--sentinel"},
							ImagePullPolicy: pullPolicy,
							Ports:           ports,
							//Env:             mergeENV(cr.Spec.AppEnv),
							Resources: corev1.ResourceRequirements{
								Limits:   resourcesLimits,
								Requests: resourcesRequests,
							},
							LivenessProbe: &corev1.Probe{
								InitialDelaySeconds: int32(30),
								TimeoutSeconds:      int32(5),
								PeriodSeconds:       int32(10),
								Handler: corev1.Handler{
									Exec: &corev1.ExecAction{
										Command: []string{"/bin/sh", "-c", "redis-cli -h $(hostname) -p 26379 ping"},
									},
								},
							},
							ReadinessProbe: &corev1.Probe{
								InitialDelaySeconds: int32(30),
								TimeoutSeconds:      int32(5),
								PeriodSeconds:       int32(10),
								Handler: corev1.Handler{
									Exec: &corev1.ExecAction{
										Command: []string{"/bin/sh", "-c", "redis-cli -h $(hostname) -p 26379 ping"},
									},
								},
							},
							VolumeMounts: []corev1.VolumeMount{
								{
									Name:      "config-rw",
									MountPath: "/redis",
								},
								{
									Name:      "config-ro",
									MountPath: "/redis-ro",
								},
								{
									Name:      "data",
									MountPath: "/redis/data",
								},
							},
						},
					},
					Volumes: []corev1.Volume{
						{
							Name: "config-rw",
							VolumeSource: corev1.VolumeSource{
								EmptyDir: &corev1.EmptyDirVolumeSource{},
							},
						},
						{
							Name: "data",
							VolumeSource: corev1.VolumeSource{
								EmptyDir: &corev1.EmptyDirVolumeSource{},
							},
						},
						{
							Name: "config-ro",
							VolumeSource: corev1.VolumeSource{
								ConfigMap: &corev1.ConfigMapVolumeSource{
									LocalObjectReference: corev1.LocalObjectReference{
										Name: cr.Name + "-sentinel",
									},
								},
							},
						},
					},
				},
			},
		},
	}

	if cr.Spec.SentinelNodeSelector != nil {
		deployment.Spec.Template.Spec.NodeSelector = *cr.Spec.SentinelNodeSelector
	}

	if cr.Spec.SentinelTolerations != nil {
		deployment.Spec.Template.Spec.Tolerations = *cr.Spec.SentinelTolerations
	}

	return deployment
}
